/*
 *  testKernelLock.c
 *  User program that tests the capabilities of kernel lock
 *
 */

#include "syscall.h"

#define NULL ((char *)0)

/*
 * test1: Test if you can add multiple locks to the kernel's
 * lock table and then try to destroy one lock while it is busy.
 * Nachos will give an error message. Only when the lock owner 
 * releases it will the kernel be able to destroy the lock that
 * is destined to be destroyed.
 */
int test1()
{
	/* create a lock */
	int lockLocation0 = CreateLock("Test1Lock0", 10);
	/* acquire the lock */
	LockAcquire(lockLocation0);
	/* try to destroy lock0 while it is still in use. 
	 * It should simply mark the lock the be deleted
	 * and give an error message.
	 */
	LockDestroy(lockLocation0);
	/* release all locks - lock 0 will be destroyed on release */
	LockRelease(lockLocation0);
	return 1;
}

/*
 * test2: releasing locks using out of range numbers,
 * releasing a lock that was already destroyed,
 * releasing a lock that was never acquired
 */
int test2()
{
	int lockLocation0 = CreateLock("Test2Lock0", 10);
	int lockLocation1 = CreateLock("Test2Lock1", 10);
	LockRelease(-1);
	LockRelease(999999);
	/* perform operations on lock 0 */
	LockDestroy(lockLocation0);
	LockRelease(lockLocation0);
	/* perform operations on lock 1 */
	LockRelease(lockLocation1);
	LockDestroy(lockLocation1);
	return 1;
}

/*
 * test3: destroying locks using out of range numbers,
 * destroying a lock that never existed, destroying a
 * busy lock, destroying a lock that was already
 * destroyed
 */
int test3()
{
	int lockLocation0 = CreateLock("Test3Lock0", 10);
	int lockLocation1 = CreateLock("Test3Lock1", 10);
	
	LockDestroy(-1);
	LockDestroy(999999);
	LockDestroy(20);
	/* perform operations on lock 0 */
	LockAcquire(lockLocation0);
	LockDestroy(lockLocation0);
	LockRelease(lockLocation0);
	/* perform operations on lock 1 */
	LockDestroy(lockLocation1);
	LockDestroy(lockLocation1);
	return 1;
}

/*
 * test4: acquiring locks using out of range numbers
 * and acquiring a lock that was previoiusly destroyed
 */
int test4()
{
	int lockLocation0 = CreateLock("Test4Lock0", 10);
	int lockLocation1 = CreateLock("Test4Lock1", 10);
	int lockLocation2 = CreateLock("Test4Lock2", 10);
	/* try to acquire */
	LockAcquire(lockLocation0-100);
	LockAcquire(lockLocation0+100);
	LockAcquire(lockLocation1/2);
	LockAcquire(lockLocation1%2);
	/* finished destroy locks */
	LockDestroy(lockLocation0);
	LockDestroy(lockLocation1);
	LockRelease(lockLocation0);
	LockRelease(lockLocation1);
	LockDestroy(lockLocation2);
	LockAcquire(lockLocation2);
	return 1;
}

/* 
 * test 5: creating more than the maximum allowed number of locks
 */
int test5()
{
	int i = 0;
	int locks[61];
	/* try to go over the max number of locks by 1 */
	/* the max number of locks is 50 */
	for(i = 0 ; i < 61; i++)
	{
		/*SWrite("Locks [%d] should be in Lock index [%d]\n", 40, i, i);*/
		locks[i] = CreateLock("Test5Lock", 9);
	}
	/* acquire, release, and destroy all 50 locks */
	for(i = 0 ; i < 60 ; i++)
	{
		LockAcquire(locks[i]);
		LockRelease(locks[i]);
		LockDestroy(locks[i]);
	}
	return 1;
}

/* 
 * test 6: passing in invalid strlens during lock creation
 */
int test6()
{
	int lockLocation0 = CreateLock("Test6Lock0", 0);
	int lockLocation1 = CreateLock("Test6Lock1", -1);
	int lockLocation2 = CreateLock("Test6Lock2", 101);
	return 1;
}


int main()
{
	int i = 0;
	Write("\n**** RUN TEST 1 ****\n", 22, ConsoleOutput);
	if(test1() != 1)
	{
		return -1;
	}
	Write("\n**** RUN TEST 2 ****\n", 22, ConsoleOutput);
	if(test2() != 1)
	{
		return -1;
	}
	Write("\n**** RUN TEST 3 ****\n", 22, ConsoleOutput);
	if(test3() != 1)
	{
		return -1;
	}
	Write("\n**** RUN TEST 4 ****\n", 22, ConsoleOutput);
	if(test4() != 1)
	{
		return -1;
	}
	Write("\n**** RUN TEST 5 ****\n", 22, ConsoleOutput);
	if(test5() != 1)
	{
		return -1;
	}
	Write("\n**** RUN TEST 6 ****\n", 22, ConsoleOutput);
	if(test6() != 1)
	{
		return -1;
	}
	Write("\n", 1, ConsoleOutput);
	Exit(0);
}


